
#include "stdafx.h"

#include "MediaStreamSinkDialogData.h"

#include "../Common/CmdHelper.h"

#include <Shlobj.h>

using namespace _DSHOWLIB_NAMESPACE;

struct tUncompressedFormat
{
    GUID			id;
    const wchar_t*	pName;
};

/* */
static const tUncompressedFormat s_UncompressedFormatList[] =
{
    { MEDIASUBTYPE_RGB32,   L"Uncompressed RGB32" },
    { MEDIASUBTYPE_RGB24,   L"Uncompressed RGB24" },
    { MEDIASUBTYPE_Y800,    L"Uncompressed Y800" },
    { MEDIASUBTYPE_UYVY,    L"Uncompressed UYVY" },
};

static const int s_UncompressedFormatListCount = sizeof( s_UncompressedFormatList ) / sizeof( s_UncompressedFormatList[0] );

CMediaStreamSinkDialogData::CMediaStreamSinkDialogData( smart_ptr<GrabberSinkType> pOldSink )
{
    m_ContainerList = MediaStreamContainer::getAvailableMediaStreamContainerList();
    if( m_ContainerList.empty() )
    {
        throw std::string( "Unable to get a list of available MediaStreamContainers" );
    }

    m_AllContentTypeItems.push_back( tContentType( L"Unspecified", NULL, GUID_NULL ) );

    tCodecList codecList = Codec::getAvailableCodecList();
    for( tCodecList::iterator it = codecList.begin(); it != codecList.end(); ++it ) {
        m_AllContentTypeItems.push_back( tContentType( (*it)->toStringW(), (*it), GUID_NULL ) );
    }
    
    for( int i = 0; i < s_UncompressedFormatListCount; ++i ) {
        tUncompressedFormat uncompr = s_UncompressedFormatList[i];
        m_AllContentTypeItems.push_back( tContentType( uncompr.pName, NULL, uncompr.id ) );
    }


    if( (pOldSink != 0) && ((pOldSink->getSinkType() == eMEDIASTREAM_SINK) != 0) )
    {
        init( static_smart_ptr_cast<MediaStreamSink>(pOldSink) );
    }
    else
    {
        init( NULL );
    }
}

/**
 *	This function initializes the dialog data.
 *	If a pOldSink pointer is specified, the data is initialized from this sink's settings;
 *	otherwise, default values are used.
 *
 */
void	CMediaStreamSinkDialogData::init( smart_ptr<_DSHOWLIB_NAMESPACE::MediaStreamSink> pOldSink )
{
    if( pOldSink != 0 )
    {
        m_filterList = pOldSink->getFrameFilters();

        m_FileName = pOldSink->getFilenameW();

        m_selectedContainer = 0;
        GUID container = pOldSink->getContainer()->getMediaStreamContainerID();
        for( unsigned int i = 0; i < m_ContainerList.size(); ++i )
        {
            if( m_ContainerList.at( i )->getMediaStreamContainerID() == container )
            {
                m_selectedContainer = i;
            }
        }

        smart_ptr<Codec> pCodec = pOldSink->getCodec();
        if( pCodec != NULL )
        {
            m_CurrentlySelectedContentType = tContentType( pCodec->toStringW(), pCodec, GUID_NULL );
        }

        GUID uncompressed = pOldSink->getSubType();
        if( uncompressed != GUID_NULL )
        {
            for( unsigned int i = 0; i < s_UncompressedFormatListCount; ++i )
            {
                if( s_UncompressedFormatList[i].id == uncompressed )
                {
                    m_CurrentlySelectedContentType = tContentType( s_UncompressedFormatList[i].pName, NULL, uncompressed );
                }
            }
        }
    }
    else
    {
        m_selectedContainer = 0;

        std::wstring fn = L"video.";
        fn += getSelectedContainer()->getPreferredFileExtensionW();

        TCHAR szPath[MAX_PATH] = { 0 };
        if( ::SHGetSpecialFolderPath( 0, szPath, CSIDL_PERSONAL, TRUE ) )
        {
            ::PathAppend( szPath, fn.c_str() );
            m_FileName = szPath;
        }
        else
        {
            m_FileName = fn.c_str();
        }
    }
}

smart_ptr<MediaStreamSink>	CMediaStreamSinkDialogData::createSink()
{
    smart_ptr<MediaStreamSink> pSink;
    if( m_CurrentlySelectedContentType.codec != NULL ) {
        pSink = MediaStreamSink::create( getSelectedContainer(), m_CurrentlySelectedContentType.codec, m_filterList );
    } else if( m_CurrentlySelectedContentType.uncompressed != GUID_NULL ) {
        pSink = MediaStreamSink::create( getSelectedContainer(), m_CurrentlySelectedContentType.uncompressed, m_filterList );
    } else {
        pSink = MediaStreamSink::create( getSelectedContainer(), m_filterList );
    }
    if( pSink != 0 )
    {
        pSink->setFilename( m_FileName );
    }

    return pSink;
}


smart_ptr<MediaStreamContainer>	CMediaStreamSinkDialogData::getSelectedContainer() const 
{
    return m_ContainerList.at( m_selectedContainer );
}

std::vector<std::wstring>	CMediaStreamSinkDialogData::getContainerList()
{
    return toStringArrayPtrListW( m_ContainerList );
}

std::vector<tContentType> CMediaStreamSinkDialogData::getAvailableContentTypeList() const
{
    auto selected_container = getSelectedContainer();
    std::vector<tContentType> rval;
    for( std::vector<tContentType>::const_iterator i = m_AllContentTypeItems.begin(); i != m_AllContentTypeItems.end(); ++i ) {
        const tContentType& item  = *i;
        if( item.isSupported( selected_container ) ) {
            rval.push_back( item );
        }
    }
    return rval;
}

void CMediaStreamSinkDialogData::selectContentTypeIndex( int index )
{
    auto list = getAvailableContentTypeList();
    if( index >= 0 && index < (int)list.size() ) {
        m_CurrentlySelectedContentType = list.at( index );
    }
}

std::vector<std::wstring> CMediaStreamSinkDialogData::getAvailableContentTypeStringList() const
{
    auto selected_container = getSelectedContainer();
    std::vector<std::wstring> rval;
    for( std::vector<tContentType>::const_iterator i = m_AllContentTypeItems.begin(); i != m_AllContentTypeItems.end(); ++i ) {
        const tContentType& item = *i;
        if( item.isSupported( selected_container ) ) {
            rval.push_back( item.name );
        }
    }
    return rval;
}

void						CMediaStreamSinkDialogData::selectContainer( int index )
{
    assert( index >= 0 && index < (int)m_ContainerList.size() );

    std::wstring oldExt = getSelectedContainer()->getPreferredFileExtensionW();
    m_selectedContainer = index;
    std::wstring newExt = getSelectedContainer()->getPreferredFileExtensionW();

    size_t oldExtP = m_FileName.length() - oldExt.length();
    if( m_FileName.substr( oldExtP ) == oldExt )
    {
        m_FileName = m_FileName.substr( 0, oldExtP ) + newExt;
    }
}

std::wstring	CMediaStreamSinkDialogData::getPreferredFilenameExtension()
{
    return getSelectedContainer()->getPreferredFileExtensionW();
}

void			CMediaStreamSinkDialogData::setFilename( const std::wstring& name )
{
    m_FileName = name;
}
